//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2004 Siemens AG
//
// Version: 1.1.2.5
// Date:    11. Jan. 2006
//////////////////////////////////////////////////////////////////////////////
//
//
// (C) Copyright 2007 Marvell International Ltd.
//  All Rights Reserved
//

//////////////////////////////////////////////////////////////////////////////
//
// The class CComManger manages the internal used port objects. This is
// necessary because exclusive port access is required by the RIL driver
// itself for port initialization as well as from external applications for
// data connections. This makes a locking mechanism necessary which is
// implemented in this class together with the global creation and destruction
// of the port objects. The class manages also the global port capabilities.
//
//////////////////////////////////////////////////////////////////////////////

extern DWORD g_dwModemType;
extern DWORD g_dwModemVersion;

//////////////////////////////////////////////////////////////////////////////
// The following lines define the supported capabilities of the available
// ports. Some combinations like GPRS and CSD or Cmd and Urc are possible.
//////////////////////////////////////////////////////////////////////////////
#define PORT_CAPS_CSD          0x00000001
#define PORT_CAPS_GPRS         0x00000002
#define PORT_CAPS_CMD          0x00000004
#define PORT_CAPS_URC          0x00000008
#define PORT_CAPS_RSA          0x00000010
//////////////////////////////////////////////////////////////////////////////
#define IS_ADI                 ((g_dwModemType == MODEMTYPE_SIEMENS_MC75) || (g_dwModemType == MODEMTYPE_SIEMENS_TC63))
#define ADD_RSA_AVAILABLE      FALSE
#define ADD_GPRS_AVAILABLE     FALSE
#ifdef AUXCOM_PORT
#ifdef SIEMENS_MAGNETO
#undef ADD_RSA_AVAILABLE
#undef ADD_GPRS_AVAILABLE
#ifdef SAP_SUPPORTED
#define ADD_RSA_AVAILABLE      (((g_dwModemType == MODEMTYPE_SIEMENS_AC45) && (g_dwModemVersion >= 3081)) || ((g_dwModemType == MODEMTYPE_SIEMENS_MC75) && (g_dwModemVersion >= 1150)) || (g_dwModemType == MODEMTYPE_SIEMENS_TC63))
#define ADD_GPRS_AVAILABLE     (IS_ADI || (g_dwModemType == MODEMTYPE_SIEMENS_AC45) && (g_dwModemVersion >= 3086))
#else
#define ADD_RSA_AVAILABLE      (FALSE)
#define ADD_GPRS_AVAILABLE     (IS_ADI || (g_dwModemType == MODEMTYPE_SIEMENS_AC45) && (g_dwModemVersion >= 3086))
#endif
#endif
#endif
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
// The following lines define the port assignments and corresponding values.
// The enum used in the past has been replaced on a dynamic port assignment
// based on the port capabilities defined globally.
//////////////////////////////////////////////////////////////////////////////
typedef int COM_PORT_TYPE;
#define INVALID_PORT           -1
#define COMMAND_PORT           g_ComManager.GetCmdPort()
#define DATA_PORT              g_ComManager.GetDataPort()
#define URC_PORT               g_ComManager.GetUrcPort()
#ifdef AUXCOM_PORT
#ifdef SIEMENS_MAGNETO
#define NUMBER_OF_PORTS        4
#define NUMBER_OF_AVAILABLE_PORTS ((ADD_GPRS_AVAILABLE || ADD_RSA_AVAILABLE) ? 4 : 3)
#else
#define NUMBER_OF_PORTS        3
#define NUMBER_OF_AVAILABLE_PORTS 3
#endif
#else // AUXCOM_PORT

#define NUMBER_OF_PORTS        2
#define NUMBER_OF_AVAILABLE_PORTS 2

#endif // AUXCOM_PORT

#define RIL_BASE_PORT_NAME_NON_MUX    TEXT("COM1:")
#define RIL_BASE_PORT_TYPE            NUMBER_OF_AVAILABLE_PORTS     //
//#define RIL_SECOND_PORT_TYPE DATA_PORT

//////////////////////////////////////////////////////////////////////////////

// Max. supported length for port names
#define MAX_PORT_NAME_LEN      64

// Macros for internal syncronization
#define USAGECLASS             CNTUSAGE_Implementation
#define CNTUSAGE(Info)         CNTUSAGE_Implementation CNTUSAGE_Object(Info)
#define INCUSAGE(Ref, Info)    Ref = new CNTUSAGE_Implementation(Info)
#define DECUSAGE(Ref)          delete Ref
#define WAITNOUSAGE(Info)      SYNCBLOCK(Info.csLock); while(Info.dwCnt) Sleep(100);
#ifndef AUXCOM_PORT
#define USE_DATA_PORT_FOR_PRIORITY_COMMANDS
#endif

class CRilHandle;
class CComHandle;

class CComManager {
public:
  CComManager();
  ~CComManager();

  void           Init(CRilHandle* pRilHandle);
  void           Deinit(void);

  CRilHandle*    GetRILDevice() { return m_pRilHandle;};

  TCHAR*         GetPortName(COM_PORT_TYPE PortType);
  TCHAR*         GetInternalPortName(COM_PORT_TYPE PortType);
  TCHAR*         GetDebugName(COM_PORT_TYPE PortType) { return m_PortInfo[PortType].strDbgName; };
  BOOL           IsDataPort(COM_PORT_TYPE PortType) { return ((m_PortInfo[PortType].dwCaps & (PORT_CAPS_GPRS | PORT_CAPS_CSD)) != 0); };
  BOOL           IsRsaPort(COM_PORT_TYPE PortType) { return (ADD_RSA_AVAILABLE && ((m_PortInfo[PortType].dwCaps & PORT_CAPS_RSA) != 0)); };

  CComHandle*    CreatePortDevice(LPWSTR szRegKey);
  CComHandle*    CreatePortDevice(COM_PORT_TYPE PortType);
  BOOL           DestroyPortDevice(COM_PORT_TYPE PortType);
  BOOL           DestroyPortDevice(CComHandle* pPortDevice);
  BOOL           OpenPortDevice(COM_PORT_TYPE PortType);
  BOOL           ClosePortDevice(COM_PORT_TYPE PortType);
  BOOL           CloseAllPortDevices(void);
  BOOL           OpenBasePort(void);
  BOOL           CloseBasePort(void);
  HANDLE         GetPortHandle(COM_PORT_TYPE PortType);

  BOOL           UnlockPortDevice(COM_PORT_TYPE PortType, BOOL fRsa = FALSE);
  BOOL           LockPortDevice(COM_PORT_TYPE PortType);

  DWORD          ExternalRead(COM_PORT_TYPE PortType, LPVOID pBuf, DWORD len);
  DWORD          ExternalWrite(COM_PORT_TYPE PortType, LPCVOID pBuf, DWORD len);
  BOOL           ExternalIoControl(COM_PORT_TYPE PortType, DWORD dwCode, PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut);

  BOOL           SendPreInitCmds(COM_PORT_TYPE PortType);
  BOOL           SendInitCmds(DWORD dwStartIndex);
  BOOL           SendUnlockedInitCmds(void);

  COM_PORT_TYPE  GetPortFromContextId(DWORD dwContextId);
  COM_PORT_TYPE  GetCmdPort(void) { return m_CmdPort; };
  COM_PORT_TYPE  GetDataPort(void) { return m_DataPort; };
  COM_PORT_TYPE  GetUrcPort(void) { return m_UrcPort; };
  COM_PORT_TYPE  GetRsaPort(void) { return (ADD_RSA_AVAILABLE ? m_RsaPort : INVALID_PORT); };
  COM_PORT_TYPE  GetPriorityPort(CRilHandle *pRilHandle);
  COM_PORT_TYPE  GetPriorityPortKeepOrder(CRilHandle *pRilHandle);
  COM_PORT_TYPE  GetAuxDataPort(void);
  DWORD          GetRsaMuxChn(void);
  BOOL           UnlockRsaPort(void);
  BOOL           LockRsaPort(BOOL fCallRsaExit, BOOL fRsaLeft);
  BOOL           IsRsaPortUnlocked(void);

  CRITICAL_SECTION csKeepOrder;

private:
  BOOL           IsValidPort(COM_PORT_TYPE PortType) { return ((PortType > INVALID_PORT) && (PortType < NUMBER_OF_PORTS)); };
  DWORD          GetPortInitIndex(COM_PORT_TYPE PortType);
  BOOL           GetPortRegKey(COM_PORT_TYPE PortType, TCHAR* pKey);
  static HRESULT ParseOk(LPCSTR szRsp, void*& pBlob, UINT& cbBlob, LPVOID pParam) { return(SetEvent((HANDLE)pParam) ? S_OK : E_FAIL); };
  static HRESULT ParseError(LPCSTR szRsp, LPVOID pParam) { return(SetEvent((HANDLE)pParam) ? S_OK : E_FAIL); };

  // Struct for information used to lock internal resources
  typedef struct {
    CRITICAL_SECTION   csLock;
    DWORD              dwCnt;
  } UsageLockInfo, *pUsageLockInfo;

  // Internal class to handle synchronization
  class CNTUSAGE_Implementation {
  public:
    CNTUSAGE_Implementation(pUsageLockInfo pInfo) {
      m_pInfo = pInfo;
      SYNCBLOCK(pInfo->csLock);
      (m_pInfo->dwCnt)++;
    };
    ~CNTUSAGE_Implementation() {
      (m_pInfo->dwCnt)--;
    }
  private:
    pUsageLockInfo m_pInfo;
  };

  // General structure describing the capabilities and characteristics of the module ports
  // used in a global array describing the available ports for port virtualization.
  typedef struct {
    TCHAR*  strDbgName;          // Name used in debug output
    TCHAR*  strRegName;          // Registry key holding the port's system name
    TCHAR*  strRegNameInternal;  // Registry key holding the port's internal name
    DWORD   dwCaps;              // Port capabilities using defines PORT_CAPS_
  } PortInfo, *pPortInfo;

  enum PORT_USAGE {
    USAGE_INTERNAL,              // Port is used internal in RIL driver
    USAGE_DATA,                  // Port is used for data transfer
    USAGE_RSA,                   // Port is used for Remote SIM Access
    USAGE_RSA_LEAVING            // Port is used for Remote SIM Access but RSA mode is already leaving
  };

  static const PortInfo  m_PortInfo[NUMBER_OF_PORTS];

  TCHAR                  m_szPortName[NUMBER_OF_PORTS][MAX_PORT_NAME_LEN];
  TCHAR                  m_szPortNameInternal[NUMBER_OF_PORTS][MAX_PORT_NAME_LEN];
  CComHandle*            m_pComDevice[NUMBER_OF_PORTS];
  UsageLockInfo          m_PortLock[NUMBER_OF_PORTS];
  PORT_USAGE             m_PortUsage[NUMBER_OF_PORTS];
  DWORD                  m_dwIoCount[NUMBER_OF_PORTS];
  HANDLE                 m_hBasePort;
  UsageLockInfo          m_RilHandleLock;
  CRilHandle*            m_pRilHandle;
  COM_PORT_TYPE          m_CmdPort;
  COM_PORT_TYPE          m_DataPort;
  COM_PORT_TYPE          m_UrcPort;
  COM_PORT_TYPE          m_AuxDataPort;
  COM_PORT_TYPE          m_RsaPort;

  BOOL     m_bInitFlag;
};

// Currently access to the CComManager is realized via a single global variable
extern CComManager g_ComManager;

//////////////////////////////////////////////////////////////////////////////
// The following lines define the AT commands used by the initialization
// in moduleinitcmds.cpp and other locations.
//////////////////////////////////////////////////////////////////////////////

//
// AT command to enable events with or without CSQ URC
// Used in misc.cpp and moduleinitcmds.cpp
//
#ifdef RIL_USE_CSQPOLLING
#define CMD_INDICATOR_CTRL          "+CIND=0,0,0,0,0,1,0,1,0"
#else
#define CMD_INDICATOR_CTRL          "+CIND=0,1,0,0,0,1,0,1,1"
#endif

